package org.kingtop.mybatis.spring;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import org.apache.ibatis.io.ResolverUtil;
import org.apache.ibatis.io.ResolverUtil.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;

/**
 * 扫描指定包的所有符合要求的类
 *
 * @author 陈金波
 * @date 2017年12月30日 上午12:19:36
 * @Copyright: 2017 chen jinbo. All rights reserved.
 */
public class UrlScanUtil {

	/**
	 * 扫描指定包的所有符合要求的类，用法如下
	 * 
	 * <pre>
	 * String packageName = "com.kingtop.**.model";
	 * UrlScanUtil.find(packageName, Object.class);
	 * </pre>
	 * 
	 * @author 陈金波
	 * @date 2017年12月30日 上午12:20:30
	 * @param packageName
	 *            包路径，可以使用*号
	 * @param superType
	 *            过滤指定继承类型的类
	 * @return
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @return Set<Class<? extends Class<?>>>
	 */
	@SuppressWarnings("unchecked")
	public static Set<Class<? extends Class<?>>> find(String packageName, Class<?> superType)
			throws IOException, ClassNotFoundException {
		ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		// 将.更换成/
		String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
				+ ClassUtils.convertClassNameToResourcePath(packageName) + "/*.class";
		// 获取其下的所有类
		Resource[] resources = resolver.getResources(pattern);
		MetadataReaderFactory factory = new CachingMetadataReaderFactory(resolver);
		Set<Class<? extends Class<?>>> typeSet = new HashSet<>();
		Test test = new ResolverUtil.IsA(superType);// 用于判断是否继承指定类
		for (Resource resource : resources) {
			if (resource.isReadable()) {
				MetadataReader reader = factory.getMetadataReader(resource);
				Class<?> type = Class.forName(reader.getClassMetadata().getClassName());
				if (test.matches(type)) {
					typeSet.add((Class<? extends Class<?>>) type);
				}
			}
		}
		return typeSet;
	}

}
